/**
 *  @file CFString.h
 */
#ifndef _CFSTRING_H_
#define _CFSTRING_H_

#include "../common/BaseObject.h"

namespace cppflib
{


class CFString;

/*
 *  global functions
 */
_DLLAPI CFString operator+(const CFString& string1, const CFString& string2);
_DLLAPI CFString operator+(const CFString& string, wc_t ch);
_DLLAPI CFString operator+(wc_t ch, const CFString& string);
_DLLAPI CFString operator+(const CFString& string, char ch);
_DLLAPI CFString operator+(char ch, const CFString& string);
_DLLAPI CFString operator+(const CFString& string, pcwstr_t lpsz);
_DLLAPI CFString operator+(pcwstr_t lpsz, const CFString& string);
_DLLAPI CFString operator+(const CFString& string, const char * psz);
_DLLAPI CFString operator+(const char * psz, const CFString& string);

_DLLAPI bool operator==(const CFString& s1, const CFString& s2);
_DLLAPI bool operator==(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator==(pcwstr_t s1, const CFString& s2);
_DLLAPI bool operator!=(const CFString& s1, const CFString& s2);
_DLLAPI bool operator!=(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator!=(pcwstr_t s1, const CFString& s2);
_DLLAPI bool operator<(const CFString& s1, const CFString& s2);
_DLLAPI bool operator<(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator<(pcwstr_t s1, const CFString& s2);
_DLLAPI bool operator>(const CFString& s1, const CFString& s2);
_DLLAPI bool operator>(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator>(pcwstr_t s1, const CFString& s2);
_DLLAPI bool operator<=(const CFString& s1, const CFString& s2);
_DLLAPI bool operator<=(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator<=(pcwstr_t s1, const CFString& s2);
_DLLAPI bool operator>=(const CFString& s1, const CFString& s2);
_DLLAPI bool operator>=(const CFString& s1, pcwstr_t s2);
_DLLAPI bool operator>=(pcwstr_t s1, const CFString& s2);



/**
 *  @brief A standalone string class to mimic the MFC "CString".
 *
 *  Most of the functions of CString are implemented. Internally,
 *  it uses Unicode (UTF-16 little endian) to represent the string
 *  characters.
 */
class _DLLAPI CFString : public BaseObject
{

private:
    pwstr_t m_szString; ///< actual pointer to string (null terminated)
    int m_nLen;         ///< length of the string in character (not counting NULL at the end)
    int m_nSize;        ///< actual size of string buffer in character (includes terminating null, may be larger than length)
    int m_attrib;       ///< attribute of this instance

private:
    // private constructors for internal use
    explicit CFString(const void * lpsz);
    explicit CFString(void * lpsz);

    void InitInternalMember(void);
    bool InitUTF8ToWideString(const char * psz, int nLen, int nSize, bool isAppend = false);
    bool InitUTF16ToWideString(pcwstr_t lpsz, int nLen, int nSize, bool isAppend = false);
    int ReAllocBuffer(int requestSize);  
    void Attach(pwstr_t lpsz);
    void Attach(const CFString &stringSrc);
    pwstr_t Detach(void);  
    void ConcatString(pcwstr_t string, int len);
    void ConcatString(const char * string, int len);
    pwstr_t GetSubString(int nStart, int nCount, bool isReverse = false) const;
    int InsertWriteLenAndSize(int nIndex, pcwstr_t psz, int nSize);
    int InsertWriteLenAndSize(int nIndex, const char * psz, int nSize);
    int Insert(int nIndex, pcwstr_t psz, int nSize);
    int Insert(int nIndex, const char * psz, int nSize);
    void ChangeCase(int upper, int lower, int disp);
    void TrimLeftChars(pcwstr_t pszTargets);
    void TrimRightChars(pcwstr_t pszTargets);

    // internal use only
    PRIVATE void __WriteStrLenAndSize(CFString *pStr);
    
public:
	CFString(void);
    explicit CFString(const char * psz);
    CFString(const char * psz, int nLen, int nSize = 0);
    explicit CFString(pcwstr_t lpsz);
    CFString(pcwstr_t lpsz, int nLen, int nSize = 0);
    CFString(const CFString &szSrc, int nSize = 0);
	virtual ~CFString(void);

public:
	int Compare(pcwstr_t szString) const;
	int CompareNoCase(pcwstr_t szString) const;

    int Delete(int iIndex, int nCount = 1);

    int Find(pcwstr_t pszSub, int iStart = 0) const;
    int FindNoCase(pcwstr_t pszSub, int iStart = 0) const;
    int Find(wc_t ch, int iStart = 0) const;
    int FindOneOf(pcwstr_t pszCharSet, int iStart = 0) const;
    int ReverseFind(wc_t ch) const;

    bool StartsWith(wc_t ch) const;
    bool StartsWith(pcwstr_t szString) const;
    bool EndsWith(wc_t ch) const;
    bool EndsWith(pcwstr_t szString) const;

    void Format(pcwstr_t pszFormat, ...);
    void AppendFormat(pcwstr_t pszFormat, ...);
    void __InternalFormat(pcwstr_t *addrOfFormat, int strStartWriteIndex);

    void Append(pcwstr_t psz, int nLen);
    int Insert(int nIndex, pcwstr_t psz);
    int Insert(int nIndex, wc_t ch);
    int Insert(int nIndex, const char * psz);
    int Remove(wc_t chRemove);

    int Replace(wc_t chOld, wc_t chNew);
    int Replace(pcwstr_t pszOld, pcwstr_t pszNew);

    CFString Left(int nCount) const;
    CFString Right(int nCount) const;
    CFString Mid(int iFirst, int nCount = -1) const;

#ifdef WIN32
    bool LoadString(ptrany_t hInstance, u32_t nID);
    bool LoadString(u32_t nID);
#endif

    CFString& MakeLower();
    CFString& MakeUpper();
    CFString& MakeReverse();

    CFString Tokenize(pcwstr_t pszTokens, int& nStart) const;

    CFString& Trim(wc_t chTarget);
    CFString& Trim(pcwstr_t pszTargets);
    CFString& Trim( );

    CFString& TrimLeft(wc_t chTarget);
    CFString& TrimLeft(pcwstr_t pszTargets);
    CFString& TrimLeft( );

    CFString& TrimRight(wc_t chTarget);
    CFString& TrimRight(pcwstr_t pszTargets);
    CFString& TrimRight( );

    bool IsEmpty() const;
    int GetLength() const;
    int SetLength(int len);
    int GetSize() const;
    
    wc_t GetAt(int index) const;
    void SetAt(int index, wc_t ch);

    bool ToUtf8String(char ** buf, int * nrChars) const;
    bool ToUtf8String(char * buf, int nrChars, int * length) const;
    char * ToUtf8String(void) const;

    /************************
     *  from BaseObject
     ************************/
    virtual bool Equals(const BaseObject &obj) const;
    virtual u32_t GetHash(void) const;
    virtual pcwstr_t ToString(void) const;

    /***********************************************
     *         operator overloading ...
     ***********************************************/
    wc_t operator[] (int nIndex) const;
    operator pcwstr_t() const;

    // assignment
    const CFString& operator=(const CFString& stringSrc);
    const CFString& operator=(wc_t ch);
    const CFString& operator=(const char * psz);
    const CFString& operator=(pcwstr_t lpsz);    

    // concatenate -- append
    const CFString& operator+=(const CFString& string);
    const CFString& operator+=(wc_t ch);
    const CFString& operator+=(const char * psz);
    const CFString& operator+=(pcwstr_t lpsz);    


    // concatenate -- these are global functions
    friend _DLLAPI CFString operator+(const CFString& string1, const CFString& string2);
    friend _DLLAPI CFString operator+(const CFString& string, wc_t ch);
    friend _DLLAPI CFString operator+(wc_t ch, const CFString& string);
    friend _DLLAPI CFString operator+(const CFString& string, char ch);
    friend _DLLAPI CFString operator+(char ch, const CFString& string);
    friend _DLLAPI CFString operator+(const CFString& string, pcwstr_t lpsz);
    friend _DLLAPI CFString operator+(pcwstr_t lpsz, const CFString& string);
    friend _DLLAPI CFString operator+(const CFString& string, const char * psz);
    friend _DLLAPI CFString operator+(const char * psz, const CFString& string);

    /***********************************************
     *           public string functions
     ***********************************************/
    PUBLIC bool IsNullOrEmpty(CFString *string);
    PUBLIC CFString Empty();
    PUBLIC CFString SFormat(pcwstr_t pszFormat, ...);

    PUBLIC sz_t Strlen(const char *lpsz);
    PUBLIC sz_t WStrlen(pcwstr_t lpsz);
    PUBLIC int WStrcmp(pcwstr_t psz1, pcwstr_t psz2);
    PUBLIC int WStrncmp(pcwstr_t psz1, pcwstr_t psz2, sz_t len);
    PUBLIC int WStricmp(pcwstr_t psz1, pcwstr_t psz2);
    PUBLIC int WStrnicmp(pcwstr_t psz1, pcwstr_t psz2, sz_t len);

    PUBLIC void *Memcpy(void *pDest, const void *pSrc, sz_t size);
    PUBLIC void *Memset(void *pDest, int ch, sz_t size);
    PUBLIC bool ConvertToUtf8String(pcwstr_t src, int srcLen, char ** buf, int * nrChars);
    PUBLIC char *ConvertToUtf8String(pcwstr_t src, int srcLen);
    PUBLIC char *ConvertToUtf8String(pcwstr_t src);
};

} // end of namespace cppflib

#endif